#include"tcp_server.h"
#include<iostream>
#include<sys/types.h>
#include<sys/socket.h>
#include<stdio.h>
#include<stdlib.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<strings.h>
#include<string.h>
#include<signal.h>
#include<errno.h>



// ======== 创建链接/销毁链接 Hook 部分 =====
//创建链接之后要触发的 回调函数
conn_callback tcp_server::conn_start_cb = NULL;
void* tcp_server::conn_start_cb_args = NULL;
//销毁链接之前要触发的 回调函数
conn_callback tcp_server::conn_close_cb = NULL;
void* tcp_server::conn_close_cb_args = NULL;

//设置链接的创建hook函数
void tcp_server::set_conn_start(conn_callback cb, void *args) {
	printf("set connection start\n");
	tcp_server::conn_start_cb = cb;
	tcp_server::conn_start_cb_args = args;


}

//设置链接的销毁hook函数
void tcp_server::set_conn_close(conn_callback cb, void *args) {
	printf("set connection close\n");
	tcp_server::conn_close_cb = cb;
	tcp_server::conn_close_cb_args = args;
}


// ======= 初始化路由分发机制句柄 =============
msg_router tcp_server::_router;

void tcp_server::add_msg_router(int msgid, msg_callback *msg_cb, void* args){
	_router.register_msg_router(msgid, msg_cb, args);
}

// ==== 链接资源管理 ============================
//全部已经在线的连接信息
tcp_conn ** tcp_server::conns = NULL;

//最大容量链接个数;
int tcp_server::_max_conns = 0;      

//当前链接刻度
int tcp_server::_curr_conns = 0;

//保护_curr_conns刻度修改的锁
pthread_mutex_t tcp_server::_conns_mutex = PTHREAD_MUTEX_INITIALIZER;


//新增一个新建的连接
void tcp_server::increase_conn(int connfd, tcp_conn *conn){
	pthread_mutex_lock(&_conns_mutex);
	conns[connfd] = conn;
	_curr_conns++;
	pthread_mutex_unlock(&_conns_mutex);
}
//减少一个断开的连接
void tcp_server::decrease_conn(int connfd){
	pthread_mutex_lock(&_conns_mutex);
	conns[connfd] = NULL;
	_curr_conns--;
	pthread_mutex_unlock(&_conns_mutex);
}           
//得到当前链接的刻度
void tcp_server::get_conn_num(int *curr_conn){
	pthread_mutex_lock(&_conns_mutex);
    *curr_conn = _curr_conns;
    pthread_mutex_unlock(&_conns_mutex);
}



// 创建连接_sockfd的回调函数
void accept_callback(event_loop *loop, int fd, void *args){
	tcp_server* server = (tcp_server*)args;
	server->do_accept();
}


// 构造函数
tcp_server::tcp_server(event_loop* loop,const char* ip, uint16_t port, int maxConn, int thread_cnt){
	// 0.忽略一些无用的信号 SIGHUP  SIGPIPE
	if(signal(SIGHUP,SIG_IGN)==SIG_ERR){
		fprintf(stderr,"signal ignore SIGHUB\n");
	}

	if(signal(SIGPIPE,SIG_IGN)==SIG_ERR){
		fprintf(stderr,"signal ignore SIGHUB\n");
	}

	//1.创建socket
	_sockfd = socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC, IPPROTO_TCP);
	if(_sockfd==-1){
		fprintf(stderr,"tcp_server:socker error!\n");
		exit(1);
	}
	
	// 2.初始化地址
	struct sockaddr_in server_addr;
	bzero(&server_addr, sizeof(server_addr));
	server_addr.sin_family = AF_INET;   
	inet_aton(ip,&server_addr.sin_addr);
	server_addr.sin_port = htons(port);
	
	//2.5设置sock可以重复监听
	int opt =1;
	if(setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR,(void *)&opt, sizeof(opt))==-1){
		fprintf(stderr,"tcp_server:setsockopt error!\n");
		exit(1);
	}

	// 3.绑定端口
	if(bind(_sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr))<0){
		fprintf(stderr,"tcp_server:bind error!\n");
		exit(1);
	}
	
	// 4.监听
	if(listen(_sockfd, 500)==-1){
		fprintf(stderr,"tcp_server:listen error!\n");
		exit(1);
	}

	// 5.将形参loop添加到tcp_server的_loop中
	_loop = loop;

	// 6.初始化链接管理
	_max_conns = maxConn;

	//+3是因为stdin,stdout,stderr 已经被占用，再新开fd一定是从3开始,所以不加3就会栈溢出
	// 除此之外还有lfd，以及主线程fd
	// 子线程的epoll_fd有thread_num个，thread_queue有thread_num个
    conns = new tcp_conn*[_max_conns + 2*thread_cnt + 5];
	if (conns == NULL) {
        fprintf(stderr, "new conns[%d] error\n", _max_conns);
        exit(1);
    }

	// 7.创建线程池
	if(thread_cnt>0){
		_thread_pool = new thread_pool(thread_cnt);
		if(_thread_pool == NULL){
			fprintf(stderr, "new thread_pool error\n");
			exit(1);
		}
	}
	
	// 8.注册_sockfd读事件
	_loop->add_io_event(_sockfd, accept_callback, EPOLLIN, this);
}

// 提供创建连接的服务
void tcp_server::do_accept(){
	_addrlen = sizeof(_connaddr);
	int connfd; 				 //客户端套接字
	char client_IP[1024]; 		 //客户端IP
	while(true){
		//1.阻塞等待连接
		connfd = accept(_sockfd, (struct sockaddr *)&_connaddr, &_addrlen);
		
		if(connfd==-1){
			if(errno==EINTR){    //中断错误
				fprintf(stderr,"tcp_server:accept=EINTR!\n");
				continue;
			}
			else if(errno==EAGAIN){  //非阻塞错误
				fprintf(stderr,"tcp_server:accept=EAGAIN!\n");
				break;
			}
			else if(errno==EMFILE){  //建立连接过多,资源不足
				fprintf(stderr,"tcp_server:accept=EMFILE!\n");
				continue;
			}
			else{
				fprintf(stderr,"tcp_server:accept error!\n");
				exit(1);
			}
			
		}
		else{  //连接成功
			//输出客户端IP 端口
			printf("client ip:%s port:%d\n",
					inet_ntop(AF_INET, &_connaddr.sin_addr.s_addr, client_IP, sizeof(client_IP)),   
					ntohs(_connaddr.sin_port));         // 根据accept传出参数，获取客户端 ip 和 port 
			
			// 获取当前在线的链接数量
			int cur_conns=0;
			get_conn_num(&cur_conns);

			// 判断连接个数是否超过最大值
			if(cur_conns >= _max_conns){
				fprintf(stderr, "so many connections, max = %d\n", _max_conns);
				close(connfd);
			}
			else{
				printf("get new connection success\n");
				if(_thread_pool != NULL){
					// 多线程模式
					// 将connfd交给新线程去创建并监听
					// 1.从线程池中获取一个thread_queue
					thread_queue<task_msg>* queue = _thread_pool->get_thread();
					
					// 2.创建一个任务
					task_msg task;
					task.type = task_msg::NEW_CONN;
					task.connfd = connfd;

					// 2.将任务发送到thread_queue中
					queue->send(task);

				}
				else{
					// 单线程模式
					tcp_conn * conn = new tcp_conn(connfd, _loop);
					if(conn==NULL){
						fprintf(stderr,"new tcp_conn error\n");
						exit(1);
					}

				}
				
			}

			break;
			//可以添加心跳机制、添加消息队列机制
		}
		
	}
}

// 析构函数
tcp_server::~tcp_server(){
	close(_sockfd);
}


// 添加一个新任务
void tcp_server::set_task(task_func func, void* args){
	_thread_pool->send_task(func, args);
}